#ifndef CPIR_SOCKET_H
#define CPIR_SOCKET_H

#include "common.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")

//   Copyright 2011 CPIR Team
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

//SerializationCore 
struct SerializationCore 
{
	char* ptr;
	int32_t size;
	int32_t refCnt;
};

//Serialization
class Serialization
{
	SerializationCore* core;

	void releasePtr()
	{
		if (core) {
			if (core->refCnt > 0) {
				core->refCnt--;
			} else {
				delete core->ptr;
				delete core;
				core = NULL;
			}
		}
	}

public:	
	Serialization(char* p, const uint32_t size)
	{
		core = new SerializationCore;
		core->ptr = p;
		core->refCnt = 0;
		core->size = size;
	}
	Serialization(const Serialization& handler) 
	{
		core = handler.core;
		core->refCnt++;
	}
	~Serialization()
	{
		releasePtr();
	}
	Serialization& operator=(const Serialization& handler)
	{
		if (this == &handler) return *this;
		core = handler.core;
		core->refCnt++;
		return *this;
	}
	char* getData() const 
	{
		return core->ptr;
	}
	uint32_t getSize() const
	{
		return core->size;
	}
};

//ISerializable
class ISerializable
{
public:
	virtual const Serialization getSerialization() const = 0;
};

//Socket
class Socket 
{
	SOCKET sck_listen;
	SOCKET sck_client;	
private:	
	bool InitServerSocket(const uint32_t port);
	bool InitClientSocket(const char* host, const uint32_t port);
	void CleanUp();	
public:
	Socket();
	~Socket();

	void Close();
	void Send(const ISerializable* iserial)
	{
		Send(iserial->getSerialization());
	}
	void Send(const Serialization content);	
	// Blocked receive.
	Serialization Receive();
	// Client connect: blocked on connecting;
	bool Connect(const char* host, const uint32_t port);
	// Blocked server wait: blocked on waiting;
	void Wait(const uint32_t port);
	
};

#endif
